﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EvoAlgLib;


namespace GP
{
    class GP
    {
        static void Main(string[] args)
        {
            if (1 == 2)
            {
                LibStatics.setRandomizer(new Random());
                for (int j = 0; j < 10; j++)
                {

                    GPFactory fact = new GPFactory(3);
                    GPIndividual gpif = (GPIndividual)fact.getIndividual();
                    GPIndividual gpim = (GPIndividual)fact.getIndividual();

                    Node nf = (Node)gpif.getGenotype();
                    Node nm = (Node)gpim.getGenotype();

                    List<Individual> ps = new List<Individual>();

                    ps.Add(gpif);
                    ps.Add(gpim);

                    foreach (Individual i in ps)
                    {
                        Console.Out.WriteLine(i.plotDisplay());
                    }

                    GPCrossover cross = new GPCrossover(1);

                    ps = cross.cross(ps);
                    foreach (Individual i in ps)
                    {
                        Console.Out.WriteLine(i.plotDisplay());
                    }
                    Console.Out.WriteLine();
                }

                return;
            }

            int repetitions = 1;
            String expsufix = DateTime.Now.ToString("yyyy-MM-dd-HH-mm");
            TextWriter outfile = new StreamWriter("..\\output-" + expsufix + ".csv");
            TextWriter firstfile = new StreamWriter("..\\first-" + expsufix + ".csv");
            TextWriter midfile = new StreamWriter("..\\middle-" + expsufix + ".csv");
            TextWriter bestfile = new StreamWriter("..\\best-" + expsufix + ".csv");

            Individual superbest = null;
            for (int rep = 0; rep < repetitions; rep++)
            {

                LibStatics.setRandomizer(new Random());

                // init parameters

                int popsize = 10000;
                double p_crossover = 0.7;
                double p_mutate = 0.01;
                int generations = 100;
                int treeDepth = 6;

                IndFactory factory = new GPFactory(treeDepth);
                factory.setPMutate(p_mutate);


                Crossover crosser = new GPCrossover(p_crossover);

                //Selector selector = new BakerSUSSelector(1.5);
                TournamentSelector selector = new TournamentSelector();


                // create inital population (random)
                List<Individual> pop = new List<Individual>();
                while (pop.Count < popsize)
                {
                    pop.Add(factory.getIndividual());
                }


                // start evolution
                for (int gen = 0; gen < generations; gen++)
                {

                    // compute statistics
                    Individual best = null;
                    double avg = 0;
                    foreach (Individual ind in pop)
                    {
                        if (best == null || ind.getFitness() > best.getFitness())
                        {
                            best = ind;
                            if (superbest == null || best.getFitness() > superbest.getFitness())
                                superbest = best;
                        }
                        avg += ind.getFitness();
                    }
                    avg /= pop.Count();

                    // display stats
                    Node n = (Node)best.getGenotype();
                    Console.Out.WriteLine(gen + ", " + best.getFitness() + ", " + avg + "," );//+ n.getSize() + "," + n.getDepth());
                    //if (gen == generations - 1)
                    {
                        Console.Out.WriteLine("Best:\r\n" + best.ToString() + " - " + best.getFitness().ToString());
                        Console.Out.WriteLine(n.ToNormalString());
                    }
                    outfile.WriteLine(rep+", "+gen + ", " + best.getFitness() + ", " + avg);

                    // create next generation
                    List<Individual> newgen = new List<Individual>();
                    //selector.resetTable(pop);
                    for (int i = 0; i < popsize / 2; ++i)
                    {
                        List<Individual> parents = selector.select(pop);
                        //List<Individual> parents = selector.select();
                        foreach (Individual ind in crosser.cross(parents))
                        {
                            ind.mutate();
                            newgen.Add(ind);
                        }
                    }
                    foreach (Individual ind in pop)
                        newgen.Add(ind);
                    pop = newgen;

                    TextWriter writer;
                    if (gen == 0)
                        writer = firstfile;
                    else if (gen == generations/2)
                        writer = midfile;
                    else if (gen == generations - 1)
                        writer = bestfile;
                    else
                        continue;
                    writer.WriteLine(best.plotDisplay());
                    writer.WriteLine(n.ToNormalString());
                    writer.WriteLine(best.getFitness());
                    List<int> results = (best as GPIndividual).getResults();
                    for (int j=0;j<results.Count();j++)
                    {
                        writer.WriteLine(results[j]);
                    }

                    for (double x = -7; x <= 7; x += 0.05)
                        for (double y = -7; y <= 7; y += 0.05)
                            writer.WriteLine(x + "\t" + y + "\t" + ((Node)best.getGenotype()).dexecute(x, y));

                    writer.Close();



                }
            }
            outfile.Close();
            Console.Out.WriteLine("SuperBest: " + superbest.ToString() + " - " + (1.0 / superbest.getFitness()).ToString());
        }
    }
}
